// MGConfigurationDialog.cpp : implementation file
//

#include "stdafx.h"
#include "MGConfigurationDialog.h"
#include "MouseTracer.h"
#include "MGCfg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CMGConfigurationDialog dialog

// workaround MFC bug - no #ifndef/#endif for afximpl.h header
#if !defined(CRIT_OBJECTFACTORYLIST)
#include <..\src\afximpl.h>
#endif		//!CRIT_OBJECTFACTORYLIST

void CMGConfigurationDialog::EnumLoadedResources()
{
	//
	// search through a list of loaded extension DLLs looking for the "COMMAND_TABLE" type resource
	// excerpt from MFC Internal
	HINSTANCE hInst;
	LPCTSTR lpType = _T("COMMAND_TABLE");
	
	// first check the main module state
	AFX_MODULE_STATE *pModuleState = AfxGetModuleState();
	if (!pModuleState->m_bSystem)
	{
		hInst = AfxGetResourceHandle();
		::EnumResourceNames((HMODULE)hInst,						// module handle 
			(LPCTSTR)lpType,									// resource type
			(ENUMRESNAMEPROC)EnumNamesFunc,						// callback function
			(LONG)this);										// extra parameter
	}
	
	// check for non_system DLLs in proper order
	AfxLockGlobals(CRIT_DYNLINKLIST);
	for (CDynLinkLibrary *pDLL = pModuleState->m_libraryList; pDLL != NULL; pDLL = pDLL->m_pNextDLL)
	{
		if (!pDLL->m_bSystem && pDLL->m_hResource != NULL)
		{
			::EnumResourceNames((HMODULE)pDLL->m_hResource,		// module handle 
				(LPCTSTR)lpType,								// resource type
				(ENUMRESNAMEPROC)EnumNamesFunc,					// callback function
				(LONG)this);									// extra parameter
		}
	}
	AfxUnlockGlobals(CRIT_DYNLINKLIST);
	
	// check language specific resource next
	hInst = pModuleState->m_appLangDLL;
	if (hInst != NULL)
	{
		::EnumResourceNames((HMODULE)hInst,						// module handle 
			(LPCTSTR)lpType,									// resource type
			(ENUMRESNAMEPROC)EnumNamesFunc,						// callback function
			(LONG)this);										// extra parameter
	}
	
	// check the main system module state
	if (pModuleState->m_bSystem)
	{
		hInst = AfxGetResourceHandle();
		::EnumResourceNames((HMODULE)hInst,						// module handle 
			(LPCTSTR)lpType,									// resource type
			(ENUMRESNAMEPROC)EnumNamesFunc,						// callback function
			(LONG)this);										// extra parameter
	}
	
	// check for system DLLs in proper order
	// check for non_system DLLs in proper order
	AfxLockGlobals(CRIT_DYNLINKLIST);
	for (pDLL = pModuleState->m_libraryList; pDLL != NULL; pDLL = pDLL->m_pNextDLL)
	{
		if (pDLL->m_bSystem && pDLL->m_hResource != NULL)
		{
			::EnumResourceNames((HMODULE)pDLL->m_hResource,		// module handle 
				(LPCTSTR)lpType,								// resource type
				(ENUMRESNAMEPROC)EnumNamesFunc,					// callback function
				(LONG)this);									// extra parameter
		}
	}
	AfxUnlockGlobals(CRIT_DYNLINKLIST);
}

BOOL CALLBACK CMGConfigurationDialog::EnumNamesFunc(
				   HANDLE hModule,   // module handle 
				   LPCTSTR lpType,   // address of resource type 
				   LPTSTR lpName,    // address of resource name 
				   LONG lParam)      // extra parameter, could be used for error checking 
{ 
	// Find the languages of all resources of type 
	// lpType and name lpName. 
    EnumResourceLanguages((HMODULE)hModule, 
        lpType, 
        lpName, 
		(ENUMRESLANGPROC)EnumLangsFunc, 
        lParam); 
	
    return TRUE; 
} 

BOOL CALLBACK CMGConfigurationDialog::EnumLangsFunc(
				   HANDLE hModule,  // module handle 
				   LPCTSTR lpType,  // address of resource type 
				   LPCTSTR lpName,  // address of resource name 
				   WORD wLang,      // resource language 
				   LONG lParam)     // extra parameter, could be used for error checking 
{ 
    HANDLE hResInfo; 
	
    hResInfo = FindResourceEx((HMODULE)hModule, lpType, lpName, wLang); 
	
	if (hResInfo)
	{
		// COMMAND_TABLE into global memory
		HRSRC hResLoad = (HRSRC)::LoadResource((HMODULE)hModule, (HRSRC)hResInfo);
		if (hResLoad)
		{
			// lock the html file into global memory
			LPVOID lpResLock = ::LockResource(hResLoad);
			if (lpResLock)
			{
				DWORD dwResourceSize =  SizeofResource((HMODULE)hModule, (HRSRC)hResInfo);
				
				BYTE *lpbResource = (BYTE *)lpResLock;
				
				CMGConfigurationDialog *pThis = (CMGConfigurationDialog *)lParam;
				ASSERT(pThis);
				ASSERT_VALID(pThis);
				
				pThis->ExtractCommandsFromResource(lpbResource, dwResourceSize);
			}
			::UnlockResource(hResLoad);
		}
	}
	
    return TRUE; 
} 

CMGConfigurationDialog::CMGConfigurationDialog(CWnd* pParent /*=NULL*/)
	: CDialog(CMGConfigurationDialog::IDD, pParent), m_bWheelCommand(FALSE), m_nGestureSelected(-1), m_bInitDialog(FALSE)
{
	//{{AFX_DATA_INIT(CMGConfigurationDialog)
	//}}AFX_DATA_INIT
}

void CMGConfigurationDialog::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CMGConfigurationDialog)
	DDX_Control(pDX, IDC_BU_LOAD_GESTURES, c_buLoadGestures);
	DDX_Control(pDX, IDC_BU_SAVE_GESTURES, c_buSaveGestures);
	DDX_Control(pDX, IDC_BU_APPLY, c_buApply);
	DDX_Control(pDX, IDC_CB_ENABLE_DOUBLE_CLICK_SCROLLING, c_cbEnableDoubleClickScrolling);
	DDX_Control(pDX, IDC_CB_USE_MIDDLE_BUTTON_FOR_DOUBLE_CLICK_SCROLLING, c_cbUseMiddleButtonForDoubleClickScrolling);
	DDX_Control(pDX, IDC_CB_PAGE_UP_DOWN, c_cbPageUpDown);
	DDX_Control(pDX, IDC_CB_PAGE_TOP_BOTTOM, c_cbPageTopBottom);
	DDX_Control(pDX, IDC_SP_PAGE_TOP_BOTTOM_RECOGNITION_AREA, c_spPageTopBottomRecognitionArea);
	DDX_Control(pDX, IDC_ED_PAGE_TOP_BOTTOM_RECOGNITION_AREA, c_edPageTopBottomRecognitionArea);
	DDX_Control(pDX, IDC_CB_ENABLE_MG_SUSPENDING_KEY, c_cbEnableMGSuspendingKey);
	DDX_Control(pDX, IDC_CB_ENABLE_MG, c_cbEnableMG);
	DDX_Control(pDX, IDC_RB_MIDDLE_BUTTON, c_rbMiddleButton);
	DDX_Control(pDX, IDC_RB_RIGHT_BUTTON, c_rbRightButton);
	DDX_Control(pDX, IDC_CB_IDENTIFY_TARGET_WINDOW_CLASS, c_cbIdentifyTargetWindowClass);
	DDX_Control(pDX, IDC_CB_SHOW_GESTURE_RECOGNITION_ON_STATUS_BAR, c_cbShowGestureRecognitionOnStatusBar);
	DDX_Control(pDX, IDC_SP_DETECTING_REPEATED_SAME_DIRECTION_RATE, c_spDetectingRepeatedSameDirectionRate);
	DDX_Control(pDX, IDC_ED_DETECTING_REPEATED_SAME_DIRECTION_RATE, c_edDetectingRepeatedSameDirectionRate);
	DDX_Control(pDX, IDC_BU_UP, c_buUp);
	DDX_Control(pDX, IDC_BU_DOWN, c_buDown);
	DDX_Control(pDX, IDC_BU_RIGHT, c_buRight);
	DDX_Control(pDX, IDC_BU_LEFT, c_buLeft);
	DDX_Control(pDX, IDC_BU_BACKSPACE, c_buBackspace);
	DDX_Control(pDX, IDC_BU_WHEEL_UP, c_buWheelUp);
	DDX_Control(pDX, IDC_BU_WHEEL_DOWN, c_buWheelDown);
	DDX_Control(pDX, IDC_BU_LEFT_BUTTON, c_buLeftButton);
	DDX_Control(pDX, IDC_BU_MIDDLE_BUTTON, c_buMiddleButton);
	DDX_Control(pDX, IDC_BU_RIGHT_BUTTON, c_buRightButton);
	DDX_Control(pDX, IDC_LC_REGISTERED_MOUSE_GESTURES, c_lcRegisteredMouseGesture);
	DDX_Control(pDX, IDC_CB_PREEMPTIVE_MGA_BUTTON_ALWAYS, c_cbPreemptiveMGAButtonAlways);
	DDX_Control(pDX, IDC_SP_GESTURE_RECOGNITION_SENSITIVITY, c_spGestureRecognitionSensitivity);
	DDX_Control(pDX, IDC_ED_GESTURE_RECOGNITION_SENSITIVITY, c_edGestureRecognitionSensitivity);
	DDX_Control(pDX, IDC_ED_GESTURE_INPUT, c_edGestureInput);
	DDX_Control(pDX, IDC_BU_DEFAULT, c_buDefault);
	DDX_Control(pDX, IDC_RB_CTRL_KEY, c_rbCTRLKey);
	DDX_Control(pDX, IDC_RB_SHIFT_KEY, c_rbSHIFTKey);
	DDX_Control(pDX, IDC_RB_ALT_KEY, c_rbALTKey);
	DDX_Control(pDX, IDC_LB_COMMAND, c_lbCommand);
	DDX_Control(pDX, IDC_X_COMMAND_DESCRIPTION, c_xCommandDescription);
	DDX_Control(pDX, IDC_CB_CATEGORY, c_cbCategory);
	DDX_Control(pDX, IDC_BU_ADD, c_buAdd);
	DDX_Control(pDX, IDC_BU_REMOVE, c_buRemove);
	DDX_Control(pDX, IDC_CB_AUTOLOADING_ON_STARTUP, c_cbAutoloadingOnStartup);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CMGConfigurationDialog, CDialog)
	//{{AFX_MSG_MAP(CMGConfigurationDialog)
	ON_CBN_SELCHANGE(IDC_CB_CATEGORY, OnSelchangeCbCategory)
	ON_LBN_SELCHANGE(IDC_LB_COMMAND, OnSelchangeLbCommand)
	ON_BN_CLICKED(IDC_BU_UP, OnBuUp)
	ON_BN_CLICKED(IDC_BU_LEFT, OnBuLeft)
	ON_BN_CLICKED(IDC_BU_RIGHT, OnBuRight)
	ON_BN_CLICKED(IDC_BU_DOWN, OnBuDown)
	ON_BN_CLICKED(IDC_BU_WHEEL_UP, OnBuWheelUp)
	ON_BN_CLICKED(IDC_BU_WHEEL_DOWN, OnBuWheelDown)
	ON_BN_CLICKED(IDC_BU_LEFT_BUTTON, OnBuLeftButton)
	ON_BN_CLICKED(IDC_BU_MIDDLE_BUTTON, OnBuMiddleButton)
	ON_BN_CLICKED(IDC_BU_RIGHT_BUTTON, OnBuRightButton)
	ON_BN_CLICKED(IDC_BU_BACKSPACE, OnBuBackspace)
	ON_BN_CLICKED(IDC_BU_ADD, OnBuAdd)
	ON_BN_CLICKED(IDC_BU_LOAD_GESTURES, OnBuLoadGestures)
	ON_BN_CLICKED(IDC_BU_SAVE_GESTURES, OnBuSaveGestures)
	ON_BN_CLICKED(IDC_BU_APPLY, OnBuApply)
	ON_BN_CLICKED(IDC_BU_DEFAULT, OnBuDefault)
	ON_BN_CLICKED(IDC_BU_REMOVE, OnBuRemove)
	ON_EN_KILLFOCUS(IDC_ED_PAGE_TOP_BOTTOM_RECOGNITION_AREA, OnKillfocusEdPageTopBottomRecognitionArea)
	ON_EN_KILLFOCUS(IDC_ED_GESTURE_RECOGNITION_SENSITIVITY, OnKillfocusEdGestureRecognitionSensitivity)
	ON_EN_KILLFOCUS(IDC_ED_DETECTING_REPEATED_SAME_DIRECTION_RATE, OnKillfocusEdDetectingRepeatedSameDirectionRate)
	ON_EN_CHANGE(IDC_ED_GESTURE_INPUT, OnChangeEdGestureInput)
	ON_NOTIFY(LVN_ITEMCHANGED, IDC_LC_REGISTERED_MOUSE_GESTURES, OnItemchangedLcRegisteredMouseGestures)
	ON_NOTIFY(NM_KILLFOCUS, IDC_LC_REGISTERED_MOUSE_GESTURES, OnKillfocusLcRegisteredMouseGestures)
	//}}AFX_MSG_MAP
	ON_BN_CLICKED(IDC_CB_USE_MIDDLE_BUTTON_FOR_DOUBLE_CLICK_SCROLLING, OnButtonClicked)
	ON_BN_CLICKED(IDC_CB_ENABLE_MG, OnButtonClicked)
	ON_BN_CLICKED(IDC_RB_MIDDLE_BUTTON, OnButtonClicked)
	ON_BN_CLICKED(IDC_RB_RIGHT_BUTTON, OnButtonClicked)
	ON_BN_CLICKED(IDC_CB_ENABLE_MG_SUSPENDING_KEY, OnButtonClicked)
	ON_BN_CLICKED(IDC_RB_CTRL_KEY, OnButtonClicked)
	ON_BN_CLICKED(IDC_RB_SHIFT_KEY, OnButtonClicked)
	ON_BN_CLICKED(IDC_RB_ALT_KEY, OnButtonClicked)
	ON_BN_CLICKED(IDC_CB_ENABLE_DOUBLE_CLICK_SCROLLING, OnButtonClicked)
	ON_BN_CLICKED(IDC_CB_PAGE_UP_DOWN, OnButtonClicked)
	ON_BN_CLICKED(IDC_CB_PAGE_TOP_BOTTOM, OnButtonClicked)
	ON_BN_CLICKED(IDC_CB_PREEMPTIVE_MGA_BUTTON_ALWAYS, OnButtonClicked)
	ON_BN_CLICKED(IDC_CB_SHOW_GESTURE_RECOGNITION_ON_STATUS_BAR, OnButtonClicked)
	ON_BN_CLICKED(IDC_CB_IDENTIFY_TARGET_WINDOW_CLASS, OnButtonClicked)
	ON_BN_CLICKED(IDC_CB_AUTOLOADING_ON_STARTUP, OnButtonClicked)
	ON_EN_CHANGE(IDC_ED_GESTURE_RECOGNITION_SENSITIVITY, OnEditChanged)
	ON_EN_CHANGE(IDC_ED_DETECTING_REPEATED_SAME_DIRECTION_RATE, OnEditChanged)
	ON_EN_CHANGE(IDC_ED_TOGGLE_PREEMPTIVE_MGA_BUTTON_MODE, OnEditChanged)
	ON_EN_CHANGE(IDC_ED_PAGE_TOP_BOTTOM_RECOGNITION_AREA, OnEditChanged)
	ON_NOTIFY(LVN_GETINFOTIP, IDC_LC_REGISTERED_MOUSE_GESTURES, OnInfoTip)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMGConfigurationDialog message handlers
void CMGConfigurationDialog::OnOK() 
{
	// TODO: Add extra validation here
	UpdateMGOptions(TRUE);

	MGCfg::Get().UpdateRegistry(TRUE);
	
	if (MGCfg::Get().Option().IsMGEnabled())
	{
		MouseTracer::Setup(AfxGetInstanceHandle());
	}
	else
	{
		MouseTracer::Remove();
		MGCfg::Cleanup();
	}
	
	CDialog::OnOK();
}

void CMGConfigurationDialog::OnCancel() 
{
	// TODO: Add extra cleanup here
	MGCfg::Get().UpdateRegistry(FALSE);
	
	CDialog::OnCancel();
}

IDData CMGConfigurationDialog::VSCommandCategories[] =
{
	{ IDS_CAT_FILE,			(DWORD)CCommandListBox::CAT_FILE },
	{ IDS_CAT_EDIT,			(DWORD)CCommandListBox::CAT_EDIT },
	{ IDS_CAT_VIEW,			(DWORD)CCommandListBox::CAT_VIEW },
	{ IDS_CAT_WIZARDBAR,	(DWORD)CCommandListBox::CAT_WIZARDBAR },
	{ IDS_CAT_INSERT,		(DWORD)CCommandListBox::CAT_INSERT },
	{ IDS_CAT_PROJECT,		(DWORD)CCommandListBox::CAT_PROJECT },
	{ IDS_CAT_BUILD,		(DWORD)CCommandListBox::CAT_BUILD },
	{ IDS_CAT_DEBUG,		(DWORD)CCommandListBox::CAT_DEBUG },
	{ IDS_CAT_IMAGE,		(DWORD)CCommandListBox::CAT_IMAGE },
	{ IDS_CAT_LAYOUT,		(DWORD)CCommandListBox::CAT_LAYOUT },
	{ IDS_CAT_QUERY,		(DWORD)CCommandListBox::CAT_QUERY },
	{ IDS_CAT_DIAGRAM,		(DWORD)CCommandListBox::CAT_DIAGRAM },
	{ IDS_CAT_TOOLS,		(DWORD)CCommandListBox::CAT_TOOLS },
	{ IDS_CAT_WINDOW,		(DWORD)CCommandListBox::CAT_WINDOW },
	{ IDS_CAT_HELP,			(DWORD)CCommandListBox::CAT_HELP },
	{ IDS_CAT_MACROS,		(DWORD)CCommandListBox::CAT_MACROS },
	{ IDS_CAT_ADDINS,		(DWORD)CCommandListBox::CAT_ADDINS },
	{ IDS_CAT_ALL,			(DWORD)CCommandListBox::CAT_ALL },
	{ 0,					(DWORD)0 }
};

BOOL CMGConfigurationDialog::OnInitDialog() 
{
	CDialog::OnInitDialog();
	
	// TODO: Add extra initialization here

	// initialize list control
	c_lcRegisteredMouseGesture.InsertColumn(0, _T("Gesture"), LVCFMT_LEFT, 150);
	c_lcRegisteredMouseGesture.InsertColumn(1, _T("Command"), LVCFMT_LEFT, 150);
	c_lcRegisteredMouseGesture.InsertColumn(2, _T("Command ID"), LVCFMT_LEFT, 100);
	ListView_SetExtendedListViewStyle(c_lcRegisteredMouseGesture.GetSafeHwnd(), LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP);
	
	c_xCommandDescription.SetWindowText(_T(""));
	
	// initialize combo box
	c_cbCategory.Load(CMGConfigurationDialog::VSCommandCategories);
	c_cbCategory.Select(CCommandListBox::CAT_ALL);
	
	// initialize list box
	EnumLoadedResources();
	
	// initialize spin controls
	c_spPageTopBottomRecognitionArea.SetRange(0, MG::PageTopBottomRecognitionAreaMax);
	c_spGestureRecognitionSensitivity.SetRange(MG::GestureRecognitionSensitivityMin, MG::GestureRecognitionSensitivityMax);
	c_spDetectingRepeatedSameDirectionRate.SetRange(MG::DetectingRepeatedSameDirectionRateMin, MG::DetectingRepeatedSameDirectionRateMax);
	
	MGCfg::Get().UpdateRegistry(FALSE);
	UpdateMGOptions(FALSE);
	UpdateChecksum();
	UpdateRegistredGestureList();
	UpdateControls();

	m_bInitDialog = TRUE;
	
	return TRUE;  // return TRUE unless you set the focus to a control
	// EXCEPTION: OCX Property Pages should return FALSE
}


int CMGConfigurationDialog::ExtractCommandsFromResource(const BYTE * lpbBuffer, DWORD dwResourceSize)
{
	return c_lbCommand.ExtractCommandsFromResource(lpbBuffer, dwResourceSize);
}

void CMGConfigurationDialog::OnSelchangeCbCategory() 
{
	// TODO: Add your control notification handler code here
	int iCurSel = c_cbCategory.GetCurSel();
	if(CB_ERR == iCurSel)
		iCurSel = CCommandListBox::CAT_ALL;

	c_lbCommand.Reload(CCommandListBox::CATEGORIES(iCurSel));
	
	UpdateControls();
}

void CMGConfigurationDialog::OnSelchangeLbCommand() 
{
	// TODO: Add your control notification handler code here
	int nIndex = c_lbCommand.GetCurSel();
	if (nIndex != LB_ERR)
	{
		WORD wID = ((LPVSCOMMAND)c_lbCommand.GetItemDataPtr(nIndex))->wID;
		CString strDescription;
		strDescription.Format(_T("%s (%d)"), ((LPVSCOMMAND)c_lbCommand.GetItemDataPtr(nIndex))->pszLongDescription, wID);
		c_xCommandDescription.SetWindowText(strDescription);
		
		UpdateControls();
	}
}

void CMGConfigurationDialog::UpdateRegistredGestureList()
{
	if (::IsWindow(c_lcRegisteredMouseGesture.GetSafeHwnd()))
	{
		c_lcRegisteredMouseGesture.DeleteAllItems();

		int nGesture = MGCfg::Get().List().GetCount();
		c_lcRegisteredMouseGesture.SetItemCount(nGesture);
		for (int i = 0; i < nGesture; i++)
		{
			LPGESTURE pGesture = MGCfg::Get().List().Get(i);
			c_lcRegisteredMouseGesture.InsertItem(i, pGesture->pattern.GetAsString().c_str());
			c_lcRegisteredMouseGesture.SetItemText(i, 1, pGesture->pszID);
			CString strID;
			strID.Format(_T("%d"), pGesture->wID);
			c_lcRegisteredMouseGesture.SetItemText(i, 2, strID);
		}
	}
}

void CMGConfigurationDialog::UpdateControls()
{
	// update controls state
	BOOL bUseMouseGesture = (BOOL)c_cbEnableMG.GetCheck();
	BOOL bUseMGSuspendingKey = (BOOL)c_cbEnableMGSuspendingKey.GetCheck();
	BOOL bEnableDoubleClickScrolling = (BOOL)c_cbEnableDoubleClickScrolling.GetCheck() && (!c_cbUseMiddleButtonForDoubleClickScrolling.GetCheck() || !c_rbMiddleButton.GetCheck());
	
	c_cbCategory.EnableWindow(bUseMouseGesture);
	c_lbCommand.EnableWindow(bUseMouseGesture);
	
	int nCurSel = c_lbCommand.GetCurSel();
	CString strTemp;
	c_edGestureInput.GetWindowText(strTemp);
	c_buAdd.EnableWindow(bUseMouseGesture && nCurSel != LB_ERR && !strTemp.IsEmpty());
	
	c_buWheelUp.EnableWindow(bUseMouseGesture);
	c_buWheelDown.EnableWindow(bUseMouseGesture);
	c_buUp.EnableWindow(bUseMouseGesture);
	c_buLeft.EnableWindow(bUseMouseGesture);
	c_buRight.EnableWindow(bUseMouseGesture);
	c_buDown.EnableWindow(bUseMouseGesture);
	c_buBackspace.EnableWindow(bUseMouseGesture);
	c_buLeftButton.EnableWindow(bUseMouseGesture);
	c_buMiddleButton.EnableWindow(bUseMouseGesture && c_rbMiddleButton.GetCheck() == 0);
	c_buRightButton.EnableWindow(bUseMouseGesture && c_rbMiddleButton.GetCheck() == 1);
	
	c_lcRegisteredMouseGesture.EnableWindow(bUseMouseGesture);
	c_buRemove.EnableWindow(bUseMouseGesture && m_nGestureSelected != -1);
	
	c_rbMiddleButton.EnableWindow(bUseMouseGesture);
	c_rbRightButton.EnableWindow(bUseMouseGesture);
	
	c_cbEnableMGSuspendingKey.EnableWindow(bUseMouseGesture);
	c_rbCTRLKey.EnableWindow(bUseMouseGesture && bUseMGSuspendingKey);
	c_rbSHIFTKey.EnableWindow(bUseMouseGesture && bUseMGSuspendingKey);
	c_rbALTKey.EnableWindow(bUseMouseGesture && bUseMGSuspendingKey);
	
	c_cbEnableDoubleClickScrolling.EnableWindow(bUseMouseGesture && (!c_cbUseMiddleButtonForDoubleClickScrolling.GetCheck() || !c_rbMiddleButton.GetCheck()));
	c_cbPageUpDown.EnableWindow(bUseMouseGesture && bEnableDoubleClickScrolling);
	c_cbPageTopBottom.EnableWindow(bUseMouseGesture && bEnableDoubleClickScrolling);
	c_edPageTopBottomRecognitionArea.EnableWindow(bUseMouseGesture && bEnableDoubleClickScrolling && (BOOL)c_cbPageTopBottom.GetCheck());
	c_spPageTopBottomRecognitionArea.EnableWindow(bUseMouseGesture && bEnableDoubleClickScrolling && (BOOL)c_cbPageTopBottom.GetCheck());

	c_cbUseMiddleButtonForDoubleClickScrolling.EnableWindow(bUseMouseGesture && bEnableDoubleClickScrolling);
	
	c_edGestureRecognitionSensitivity.EnableWindow(bUseMouseGesture);
	c_spGestureRecognitionSensitivity.EnableWindow(bUseMouseGesture);
	c_edDetectingRepeatedSameDirectionRate.EnableWindow(bUseMouseGesture);
	c_spDetectingRepeatedSameDirectionRate.EnableWindow(bUseMouseGesture);
	
	c_cbPreemptiveMGAButtonAlways.EnableWindow(bUseMouseGesture);
	c_cbShowGestureRecognitionOnStatusBar.EnableWindow(bUseMouseGesture);
	c_cbIdentifyTargetWindowClass.EnableWindow(bUseMouseGesture && (BOOL)c_cbShowGestureRecognitionOnStatusBar.GetCheck());
	c_cbAutoloadingOnStartup.EnableWindow(bUseMouseGesture);
	
	c_buApply.EnableWindow(IsModified());
}

void CMGConfigurationDialog::DoChecksum(checksum &rChecksum)
{
	CString strTemp;
	
	rChecksum.add((BOOL)c_rbMiddleButton.GetCheck());
	rChecksum.add((BOOL)c_rbRightButton.GetCheck());
	
	rChecksum.add((BOOL)c_cbEnableMGSuspendingKey.GetCheck());
	rChecksum.add((BOOL)c_rbCTRLKey.GetCheck());
	rChecksum.add((BOOL)c_rbSHIFTKey.GetCheck());
	rChecksum.add((BOOL)c_rbALTKey.GetCheck());
	
	rChecksum.add((BOOL)c_cbEnableDoubleClickScrolling.GetCheck());
	rChecksum.add((BOOL)c_cbPageUpDown.GetCheck());
	rChecksum.add((BOOL)c_cbPageTopBottom.GetCheck());
	
	c_edPageTopBottomRecognitionArea.GetWindowText(strTemp);
	rChecksum.add(strTemp);
	c_edGestureRecognitionSensitivity.GetWindowText(strTemp);
	rChecksum.add(strTemp);
	c_edDetectingRepeatedSameDirectionRate.GetWindowText(strTemp);
	rChecksum.add(strTemp);
	
	rChecksum.add((BOOL)c_cbPreemptiveMGAButtonAlways.GetCheck());
	rChecksum.add((BOOL)c_cbShowGestureRecognitionOnStatusBar.GetCheck());
	rChecksum.add((BOOL)c_cbIdentifyTargetWindowClass.GetCheck());
	rChecksum.add((BOOL)c_cbAutoloadingOnStartup.GetCheck());

	rChecksum.add((BOOL)c_cbUseMiddleButtonForDoubleClickScrolling.GetCheck());
}

void CMGConfigurationDialog::UpdateMGOptions(BOOL bSaveAndValidate)
{
	if (bSaveAndValidate)
	{
		CString strTemp;

		CMGOption<> &rOption = MGCfg::Get().Option();
		rOption.EnableMG((BOOL)c_cbEnableMG.GetCheck());
		rOption.SetMGAButton(c_rbMiddleButton.GetCheck() ? MG::BUTTON_MIDDLE : MG::BUTTON_RIGHT);
		rOption.EnableMGSuspendingKey((BOOL)c_cbEnableMGSuspendingKey.GetCheck());
		rOption.SetMGSuspendingKey(c_rbCTRLKey.GetCheck() ? MG::VIRTUAL_CONTROL :(c_rbSHIFTKey.GetCheck() ? MG::VIRTUAL_SHIFT : MG::VIRTUAL_ALT));
		rOption.EnableDblClkScrolling((BOOL)c_cbEnableDoubleClickScrolling.GetCheck());
		rOption.EnablePageUpDown((BOOL)c_cbPageUpDown.GetCheck());
		rOption.EnablePageTopBottom((BOOL)c_cbPageTopBottom.GetCheck());
		c_edPageTopBottomRecognitionArea.GetWindowText(strTemp);
		rOption.SetPageTopBottomRecognitionArea(_ttoi(strTemp));
		c_edGestureRecognitionSensitivity.GetWindowText(strTemp);
		rOption.SetGestureRecognitionSensitivity(_ttoi(strTemp));
		c_edDetectingRepeatedSameDirectionRate.GetWindowText(strTemp);
		rOption.SetDetectingRepeatedSameDirectionRate(_ttoi(strTemp));
		rOption.EnablePreemptiveMGAButtonAlways((BOOL)c_cbPreemptiveMGAButtonAlways.GetCheck());
		rOption.EnableShowRecognitionOnStatusBar((BOOL)c_cbShowGestureRecognitionOnStatusBar.GetCheck());
		rOption.EnableIdentifyTargetWindowClass((BOOL)c_cbIdentifyTargetWindowClass.GetCheck());
		rOption.EnableAutoloadingOnStartup((BOOL)c_cbAutoloadingOnStartup.GetCheck());
		rOption.EnableHelpTip(TRUE);
		rOption.SetDelayTimeHelpTip(2000);

		rOption.UseMiddleButtonForDblClkScrolling((BOOL)c_cbUseMiddleButtonForDoubleClickScrolling.GetCheck());
	}
	else
	{
		CString strTemp;

		CMGOption<> &rOption = MGCfg::Get().Option();
		c_cbEnableMG.SetCheck(rOption.IsMGEnabled());
		c_rbMiddleButton.SetCheck(MG::Button(rOption.GetMGAButton()) == MG::BUTTON_MIDDLE);
		c_rbRightButton.SetCheck(MG::Button(rOption.GetMGAButton()) == MG::BUTTON_RIGHT);
		c_cbEnableMGSuspendingKey.SetCheck(rOption.IsMGSuspendingKeyEnabled());
		c_rbCTRLKey.SetCheck(MG::VirtualKey(rOption.GetMGSuspendingKey()) == MG::VIRTUAL_CONTROL);
		c_rbSHIFTKey.SetCheck(MG::VirtualKey(rOption.GetMGSuspendingKey()) == MG::VIRTUAL_SHIFT);
		c_rbALTKey.SetCheck(MG::VirtualKey(rOption.GetMGSuspendingKey()) == MG::VIRTUAL_ALT);
		c_cbEnableDoubleClickScrolling.SetCheck(rOption.IsDblClkScrollingEnabled());
		c_cbPageUpDown.SetCheck(rOption.IsPageUpDown());
		c_cbPageTopBottom.SetCheck(rOption.IsPageTopBottom());
		strTemp.Format(_T("%d"), rOption.GetPageTopBottomRecognitionArea());
		c_edPageTopBottomRecognitionArea.SetWindowText(strTemp);
		strTemp.Format(_T("%d"), rOption.GetGestureRecognitionSensitivity());
		c_edGestureRecognitionSensitivity.SetWindowText(strTemp);
		strTemp.Format(_T("%d"), rOption.GetDetectingRepeatedSameDirectionRate());
		c_edDetectingRepeatedSameDirectionRate.SetWindowText(strTemp);
		c_cbPreemptiveMGAButtonAlways.SetCheck(rOption.IsPreemptiveMGAButtonAlways());
		c_cbShowGestureRecognitionOnStatusBar.SetCheck(rOption.IsShowRecognitionOnStatusBar());
		c_cbIdentifyTargetWindowClass.SetCheck(rOption.IsIdentifyTargetWindowClass());
		c_cbAutoloadingOnStartup.SetCheck(rOption.IsAutoLoadingOnStartup());

		c_cbUseMiddleButtonForDoubleClickScrolling.SetCheck(rOption.IsMiddleButtonForDblClkScrolling());
	}
}

void CMGConfigurationDialog::OnBuUp() 
{
	// TODO: Add your control notification handler code here
	CString strGesture;

	if(m_bWheelCommand)
		m_bWheelCommand = FALSE;
	else
		c_edGestureInput.GetWindowText(strGesture);

	strGesture += MGCfg::Get().List().GetArrowMark(MG::ARROW_UP);
	strGesture += _T(' ');

	c_edGestureInput.SetWindowText(strGesture);
	
	UpdateControls();
}

void CMGConfigurationDialog::OnBuLeft() 
{
	// TODO: Add your control notification handler code here
	CString strGesture;

	if(m_bWheelCommand)
		m_bWheelCommand = FALSE;
	else
		c_edGestureInput.GetWindowText(strGesture);

	strGesture += MGCfg::Get().List().GetArrowMark(MG::ARROW_LEFT);
	strGesture += _T(' ');
	c_edGestureInput.SetWindowText(strGesture);
	
	UpdateControls();
}

void CMGConfigurationDialog::OnBuRight() 
{
	// TODO: Add your control notification handler code here
	CString strGesture;

	if(m_bWheelCommand)
		m_bWheelCommand = FALSE;
	else
		c_edGestureInput.GetWindowText(strGesture);

	strGesture += MGCfg::Get().List().GetArrowMark(MG::ARROW_RIGHT);
	strGesture += _T(' ');
	c_edGestureInput.SetWindowText(strGesture);
	
	UpdateControls();
}

void CMGConfigurationDialog::OnBuDown() 
{
	// TODO: Add your control notification handler code here
	CString strGesture;

	if(m_bWheelCommand)
		m_bWheelCommand = FALSE;
	else
		c_edGestureInput.GetWindowText(strGesture);

	strGesture += MGCfg::Get().List().GetArrowMark(MG::ARROW_DOWN);
	strGesture += _T(' ');
	c_edGestureInput.SetWindowText(strGesture);
	
	UpdateControls();
}

void CMGConfigurationDialog::OnBuLeftButton() 
{
	// TODO: Add your control notification handler code here
	CString strGesture;

	if(m_bWheelCommand)
		m_bWheelCommand = FALSE;
	else
		c_edGestureInput.GetWindowText(strGesture);

	strGesture += MGCfg::Get().List().GetKeyMark(MG::KEY_BUTTON1);
	strGesture += _T(' ');
	c_edGestureInput.SetWindowText(strGesture);
	
	UpdateControls();
}

void CMGConfigurationDialog::OnBuMiddleButton() 
{
	// TODO: Add your control notification handler code here
	CString strGesture;

	if(m_bWheelCommand)
		m_bWheelCommand = FALSE;
	else
		c_edGestureInput.GetWindowText(strGesture);

	strGesture += MGCfg::Get().List().GetKeyMark(MG::KEY_BUTTON2);
	strGesture += _T(' ');
	c_edGestureInput.SetWindowText(strGesture);
	
	UpdateControls();
}

void CMGConfigurationDialog::OnBuRightButton() 
{
	// TODO: Add your control notification handler code here
	CString strGesture;

	if(m_bWheelCommand)
		m_bWheelCommand = FALSE;
	else
		c_edGestureInput.GetWindowText(strGesture);

	strGesture += MGCfg::Get().List().GetKeyMark(MG::KEY_BUTTON2);
	strGesture += _T(' ');
	c_edGestureInput.SetWindowText(strGesture);
	
	UpdateControls();
}

void CMGConfigurationDialog::OnBuWheelUp() 
{
	// TODO: Add your control notification handler code here
	CString strGesture;
	
	m_bWheelCommand = TRUE;
	strGesture += MGCfg::Get().List().GetKeyMark(MG::KEY_WHEEL_UP);
	strGesture += _T(' ');

	c_edGestureInput.SetWindowText(strGesture);
	
	UpdateControls();
}

void CMGConfigurationDialog::OnBuWheelDown() 
{
	// TODO: Add your control notification handler code here
	CString strGesture;
	
	m_bWheelCommand = TRUE;
	strGesture += MGCfg::Get().List().GetKeyMark(MG::KEY_WHEEL_DOWN);
	strGesture += _T(' ');

	c_edGestureInput.SetWindowText(strGesture);
	
	UpdateControls();
}

void CMGConfigurationDialog::OnBuBackspace() 
{
	// TODO: Add your control notification handler code here
	if (m_bWheelCommand)
	{
		m_bWheelCommand = FALSE;
		c_edGestureInput.SetWindowText(_T(""));
	}
	else
	{
		CString strGesture;
		
		c_edGestureInput.GetWindowText(strGesture);
		strGesture = strGesture.Left(strGesture.GetLength() - 2);
		c_edGestureInput.SetWindowText(strGesture);
	}
	
	UpdateControls();
}

void CMGConfigurationDialog::OnBuAdd() 
{
	// TODO: Add your control notification handler code here
	CString strGesture;
	c_edGestureInput.GetWindowText(strGesture);
	c_edGestureInput.SetWindowText(_T(""));
	
	m_bWheelCommand = FALSE;
	
	LPVSCOMMAND pCommand = c_lbCommand.GetCommand(c_lbCommand.GetCurSel());
	ASSERT(pCommand);

	std::tostringstream tss;
	tss << (LPCTSTR)strGesture << _T("\\")
		<< pCommand->pszID << _T("\\")
		<< pCommand->wID << _T("\\")
		<< pCommand->pszShortDescription << _T("\\")
		<< (BYTE)(-1);

	MGCfg::Get().List().AddFromString(tss.str().c_str());
	
	UpdateRegistredGestureList();
	UpdateControls();
}


void CMGConfigurationDialog::OnBuRemove() 
{
	// TODO: Add your control notification handler code here
	
	c_lcRegisteredMouseGesture.DeleteItem(m_nGestureSelected);
	MGCfg::Get().List().Remove(m_nGestureSelected);

	UpdateRegistredGestureList();

	int nItemCount = c_lcRegisteredMouseGesture.GetItemCount();
	m_nGestureSelected = m_nGestureSelected ==  nItemCount ? nItemCount - 1 : m_nGestureSelected;
	c_lcRegisteredMouseGesture.SetFocus();
	c_lcRegisteredMouseGesture.SetItemState(m_nGestureSelected, LVIS_SELECTED, LVIS_SELECTED | LVIS_FOCUSED);
	//	c_lcRegisteredMouseGesture.EnsureVisible(m_nGestureSelected, FALSE);

	UpdateControls();
}

void CMGConfigurationDialog::OnKillfocusEdPageTopBottomRecognitionArea() 
{
	// TODO: Add your control notification handler code here
	CString strTemp;
	c_edPageTopBottomRecognitionArea.GetWindowText(strTemp);
	int nTemp = _ttoi(strTemp);
	if (nTemp < 0)
		c_edPageTopBottomRecognitionArea.SetWindowText(_T("0"));
	else if (nTemp > MG::PageTopBottomRecognitionAreaMax)
		c_edPageTopBottomRecognitionArea.SetWindowText(_itot(MG::PageTopBottomRecognitionAreaMax, NULL, 10));
	
	UpdateControls();
}

void CMGConfigurationDialog::OnKillfocusEdGestureRecognitionSensitivity() 
{
	// TODO: Add your control notification handler code here
	CString strTemp;
	c_edGestureRecognitionSensitivity.GetWindowText(strTemp);
	int nTemp = _ttoi(strTemp);
	if (nTemp < MG::GestureRecognitionSensitivityMin)
		c_edGestureRecognitionSensitivity.SetWindowText(_itot(MG::GestureRecognitionSensitivityMin, NULL, 10));
	else if (nTemp > MG::GestureRecognitionSensitivityMax)
		c_edGestureRecognitionSensitivity.SetWindowText(_itot(MG::GestureRecognitionSensitivityMax, NULL, 10));
	
	UpdateControls();
}

void CMGConfigurationDialog::OnKillfocusEdDetectingRepeatedSameDirectionRate() 
{
	// TODO: Add your control notification handler code here
	CString strTemp;
	c_edDetectingRepeatedSameDirectionRate.GetWindowText(strTemp);
	int nTemp = _ttoi(strTemp);
	if (nTemp < MG::DetectingRepeatedSameDirectionRateMin)
		c_edDetectingRepeatedSameDirectionRate.SetWindowText(_itot(MG::DetectingRepeatedSameDirectionRateMin, NULL, 10));
	else if (nTemp > MG::DetectingRepeatedSameDirectionRateMax)
		c_edDetectingRepeatedSameDirectionRate.SetWindowText(_itot(MG::DetectingRepeatedSameDirectionRateMax, NULL, 10));
	
	UpdateControls();
}

void CMGConfigurationDialog::OnBuLoadGestures() 
{
	// TODO: Add your control notification handler code here
	static TCHAR BASED_CODE szFilter[] = _T("Mouse Gesture File (*.ini)|*.ini|All Files (*.*)|*.*||");
	CFileDialog dlgFile(TRUE, _T("ini"), NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, szFilter);
		
	if(dlgFile.DoModal() == IDCANCEL) return; 
		
	MGCfg::Get().List().Load(dlgFile.GetPathName());
		
	UpdateRegistredGestureList();
}

void CMGConfigurationDialog::OnBuSaveGestures() 
{
	// TODO: Add your control notification handler code here
	static TCHAR BASED_CODE szFilter[] = _T("Mouse Gesture File (*.ini)|*.ini|All Files (*.*)|*.*||");
	CFileDialog dlgFile(FALSE, _T("ini"), _T("Gesture.ini"), OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, szFilter);

	if(dlgFile.DoModal() == IDCANCEL) return;

	MGCfg::Get().List().Save(dlgFile.GetPathName());
}

void CMGConfigurationDialog::OnBuApply() 
{
	// TODO: Add your control notification handler code here
	UpdateMGOptions(TRUE);
	UpdateChecksum();
	UpdateControls();
}

void CMGConfigurationDialog::OnBuDefault() 
{
	// TODO: Add your control notification handler code here
	c_cbEnableMG.SetCheck(TRUE);
	c_rbRightButton.SetCheck(TRUE);
	c_rbMiddleButton.SetCheck(FALSE);
	c_cbEnableMGSuspendingKey.SetCheck(TRUE);
	c_rbCTRLKey.SetCheck(FALSE);
	c_rbSHIFTKey.SetCheck(TRUE);
	c_rbALTKey.SetCheck(FALSE);
	c_cbEnableDoubleClickScrolling.SetCheck(TRUE);
	c_cbPageUpDown.SetCheck(TRUE);
	c_cbPageTopBottom.SetCheck(TRUE);
	c_edPageTopBottomRecognitionArea.SetWindowText(_T("5"));
	c_edGestureRecognitionSensitivity.SetWindowText(_T("15"));
	c_edDetectingRepeatedSameDirectionRate.SetWindowText(_T("300"));
	c_cbPreemptiveMGAButtonAlways.SetCheck(FALSE);
	c_cbShowGestureRecognitionOnStatusBar.SetCheck(TRUE);
	c_cbIdentifyTargetWindowClass.SetCheck(FALSE);
	c_cbAutoloadingOnStartup.SetCheck(TRUE);

	c_cbUseMiddleButtonForDoubleClickScrolling.SetCheck(FALSE);
	
	UpdateControls();
}

void CMGConfigurationDialog::OnItemchangedLcRegisteredMouseGestures(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
	// TODO: Add your control notification handler code here
	if (pNMListView->uNewState & LVIS_SELECTED)
	{
		m_nGestureSelected = pNMListView->iItem;

		if(m_nGestureSelected >= 0)
		{
			LPGESTURE pGesture = MGCfg::Get().List().Get(m_nGestureSelected);
			int nIndex = c_lbCommand.FindCommand(pGesture->wID);
			if(LB_ERR != nIndex)
			{
				c_lbCommand.SetCurSel(nIndex);
				CString strDescription;
				strDescription.Format(_T("%s (%d)"), ((LPVSCOMMAND)c_lbCommand.GetItemDataPtr(nIndex))->pszLongDescription, pGesture->wID);
				c_xCommandDescription.SetWindowText(strDescription);
			}
		}
	}
	
	*pResult = 0;
	
	UpdateControls();
}

void CMGConfigurationDialog::OnInfoTip(NMHDR* pNMHDR, LRESULT* pResult)
{
	NMLVGETINFOTIP *pInfoTip = reinterpret_cast<NMLVGETINFOTIP *>(pNMHDR);
	if (pInfoTip)
	{
		LPGESTURE pGesture = MGCfg::Get().List().Get(pInfoTip->iItem);
		if (pGesture)
		{
			CString strToolTip;
			strToolTip.Format(_T("\"%s\" %s (%d)"), pGesture->pattern.GetAsString().c_str(), pGesture->pszID, pGesture->wID);
			
			_tcsncpy(pInfoTip->pszText, strToolTip, pInfoTip->cchTextMax);
		}
	}
	
	*pResult = 0;
}

void CMGConfigurationDialog::OnButtonClicked()
{
	// TODO: Add your control notification handler code here
	UpdateControls();
}

void CMGConfigurationDialog::OnEditChanged() 
{
	// TODO: Add your control notification handler code here
	if(m_bInitDialog) UpdateControls();
}

void CMGConfigurationDialog::OnChangeEdGestureInput() 
{
	// TODO: Add your control notification handler code here
	if(m_bInitDialog)
	{
		CString strGesture;
		c_edGestureInput.GetWindowText(strGesture);

		int nFound = MGCfg::Get().List().Find(strGesture);
		if(nFound >= 0)
		{
			c_lcRegisteredMouseGesture.SetFocus();
			c_lcRegisteredMouseGesture.SetItemState(nFound, LVIS_SELECTED, LVIS_SELECTED | LVIS_FOCUSED);
			c_lcRegisteredMouseGesture.EnsureVisible(nFound, FALSE);
		}
		else
		{
			c_lcRegisteredMouseGesture.SetItemState(m_nGestureSelected, !LVIS_SELECTED, LVIS_SELECTED | LVIS_FOCUSED);
			m_nGestureSelected = -1;
		}
	}
}

void CMGConfigurationDialog::OnKillfocusLcRegisteredMouseGestures(NMHDR* /*pNMHDR*/, LRESULT* pResult) 
{
	// TODO: Add your control notification handler code here
	c_lcRegisteredMouseGesture.SetItemState(m_nGestureSelected, !LVIS_SELECTED, LVIS_SELECTED | LVIS_FOCUSED);
	//	m_nGestureSelected = -1;
	
	*pResult = 0;
}
